home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / linux / atari / source / source.lzh / atari-linux-0.01pl3 / drivers / char / lp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-05  |  8.2 KB  |  399 lines

  1. /*
  2.  * Amiga printer device by Michael Rausch (linux@uni-koblenz.de);
  3.  * based upon work from
  4.  *
  5.  * Copyright (C) 1992 by Jim Weigand and Linus Torvalds
  6.  * Copyright (C) 1992,1993 by Michael K. Johnson
  7.  * - Thanks much to Gunter Windau for pointing out to me where the error
  8.  *   checking ought to be.
  9.  * Copyright (C) 1993 by Nigel Gamble (added interrupt code)
  10.  */
  11.  
  12. #include <linux/errno.h>
  13. #include <linux/kernel.h>
  14. #include <linux/major.h>
  15. #include <linux/sched.h>
  16. #include <linux/lp.h>
  17. #include <linux/malloc.h>
  18. #include <linux/interrupt.h>
  19.  
  20. #include <asm/segment.h>
  21. #include <asm/system.h>
  22.  
  23. #include <linux/amigahw.h>
  24. #include <linux/amigaints.h>
  25.  
  26. /*
  27.  *  why bother around with the pio driver when the interrupt works;
  28.  *  so, for "security" reasons only, it's configurable here.
  29.  *  saves some bytes, at least ...
  30.  */
  31. #define FORCE_POLLING     0
  32. #define FORCE_INTERRUPT     1
  33. #define PREFER_INTERRUPT 2
  34.  
  35. #define WHICH_DRIVER    FORCE_INTERRUPT
  36.  
  37. /* 
  38.  * All my debugging code assumes that you debug with only one printer at
  39.  * a time. RWWH
  40.  */
  41.  
  42. #undef LP_DEBUG
  43.  
  44. #ifdef LP_DEBUG
  45. static int lp_max_count = 1;
  46. #endif
  47.  
  48.  
  49. #if WHICH_DRIVER != FORCE_INTERRUPT
  50. static int lp_char_polled(char lpchar)
  51. {
  52.     unsigned long count  = 0; 
  53.  
  54.     do {
  55.         count ++;
  56.         if(need_resched)
  57.             schedule();
  58.     } while(LP_IS_BUSY && count < LP_CHAR);
  59.  
  60.     if (count == LP_CHAR) {
  61.         return 0;
  62.         /* we timed out, and the character was /not/ printed */
  63.     }
  64. #ifdef LP_DEBUG
  65.     if (count > lp_max_count) {
  66.         printk("lp success after %d counts.\n",count);
  67.         lp_max_count=count;
  68.     }
  69. #endif
  70.     LP_OUT(lpchar);    /* strobe is handled in hardware */
  71.     return 1;
  72. }
  73. #endif
  74.  
  75.  
  76. #ifdef LP_DEBUG
  77. unsigned int lp_total_chars = 0;
  78. unsigned int lp_last_call = 0;
  79. #endif
  80.  
  81.  
  82. #if WHICH_DRIVER != FORCE_POLLING
  83. static int lp_char_interrupt(char lpchar)
  84. {
  85.     if (!LP_IS_BUSY) {
  86.         LP_OUT(lpchar);
  87.         return 1;
  88.     }
  89.     return 0;
  90. }
  91.  
  92. static int do_print=0;
  93. static unsigned long copy_size, bytes_written;
  94.  
  95. static void lp_interrupt(void)
  96. {
  97.     if(do_print)
  98.     {
  99.         if(copy_size)
  100.         {
  101.             cli();
  102.             if (lp_char_interrupt(lp_table.lp_buffer[bytes_written])) {
  103.                 --copy_size;
  104.                 ++bytes_written;
  105.                 sti();
  106.             }
  107.             else
  108.             {
  109.                 do_print=0;
  110.                 sti();
  111.                 wake_up(&lp_table.lp_wait_q);
  112.             }
  113.         }
  114.         else
  115.         {
  116.             do_print=0;
  117.             wake_up(&lp_table.lp_wait_q);
  118.         }
  119.  
  120.     }
  121. }
  122.  
  123. #if WHICH_DRIVER == FORCE_INTERRUPT
  124. static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
  125. #else
  126. static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count)
  127. #endif
  128. {
  129.     static unsigned long total_bytes_written = 0;
  130.  
  131.     do {
  132.         bytes_written = 0;
  133.         copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
  134.         memcpy_fromfs(lp_table.lp_buffer, buf, copy_size);
  135.  
  136.         do {
  137.             cli();
  138.             do_print=1;
  139.  
  140.             /* initial output, to trigger the interrupt */
  141.             if (lp_char_interrupt(lp_table.lp_buffer[bytes_written])) {
  142.                 --copy_size;
  143.                 ++bytes_written;
  144.                 sti();
  145.  
  146.                 /* ok, now wait for the interrupt routine to get ready */
  147.                 current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
  148.                 interruptible_sleep_on(&lp_table.lp_wait_q);
  149.  
  150.                 /* just to be sure, if we timed out on this here */
  151.                 do_print=0;
  152.             }
  153.             else
  154.             {
  155.                 do_print=0;
  156.                 sti();
  157.             }
  158.  
  159.             if(copy_size) {
  160.                 int rc = total_bytes_written + bytes_written;
  161.  
  162.                 if (LP_HAS_POUT) {
  163.                     printk("lp0: out of paper\n");
  164.                     if (!rc)
  165.                         rc = -ENOSPC;
  166.                 } else if (!LP_IS_ONLINE) {
  167.                     printk("lp0: off-line\n");
  168.                     if (!rc)
  169.                         rc = -EIO;
  170.                 } else if (LP_IS_BUSY) {
  171.                     printk("lp0: printer error\n");
  172.                     if (!rc)
  173.                         rc = -EIO;
  174.                 }
  175.                 if(LP_F & LP_ABORT)
  176.                     return rc;
  177.  
  178.                 if (current->signal & ~current->blocked) {
  179.                     if (total_bytes_written + bytes_written)
  180.                         return total_bytes_written + bytes_written;
  181.                     else
  182.                         return -EINTR;
  183.                 }
  184.  
  185.                 /* cli(); */
  186.                 current->state = TASK_INTERRUPTIBLE;
  187.                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
  188.                 schedule();
  189.             }
  190.         } while(copy_size);
  191.  
  192.         total_bytes_written += bytes_written;
  193.         buf += bytes_written;
  194.         count -= bytes_written;
  195.  
  196.     } while (count > 0);
  197.  
  198.     return total_bytes_written;
  199. }
  200. #endif
  201.  
  202.  
  203. #if WHICH_DRIVER != FORCE_INTERRUPT
  204. #if WHICH_DRIVER == FORCE_POLLING
  205. static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
  206. #else
  207. static int lp_write_polled(struct inode * inode, struct file * file,
  208.                char * buf, int count)
  209. #endif
  210. {
  211.     char *temp = buf;
  212.  
  213. #ifdef LP_DEBUG
  214.     if (jiffies-lp_last_call > LP_TIME) {
  215.         lp_total_chars = 0;
  216.         lp_max_count = 1;
  217.     }
  218.     lp_last_call = jiffies;
  219. #endif
  220.  
  221.     temp = buf;
  222.     while (count > 0) {
  223.         if (lp_char_polled( get_fs_byte(temp) )) {
  224.             /* only update counting vars if character was printed */
  225.             count--; temp++;
  226. #ifdef LP_DEBUG
  227.             lp_total_chars++;
  228. #endif
  229.         } else { /* if printer timed out */
  230.             if (LP_HAS_POUT) {
  231.                 printk("lp0: out of paper\n");
  232.                 if(LP_F & LP_ABORT)
  233.                     return temp-buf?temp-buf:-ENOSPC;
  234.                 current->state = TASK_INTERRUPTIBLE;
  235.                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
  236.                 schedule();
  237.             } else
  238.             if (!LP_IS_ONLINE) {
  239.                 printk("lp0: off-line\n");
  240.                 if(LP_F & LP_ABORT)
  241.                     return temp-buf?temp-buf:-EIO;
  242.                 current->state = TASK_INTERRUPTIBLE;
  243.                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
  244.                 schedule();
  245.             } else
  246.                     /* not offline or out of paper. on fire? */
  247.             if (LP_IS_BUSY) {
  248.                 printk("lp0: on fire\n");
  249.                 if(LP_F & LP_ABORT)
  250.                     return temp-buf?temp-buf:-EFAULT;
  251.                 current->state = TASK_INTERRUPTIBLE;
  252.                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
  253.                 schedule();
  254.             }
  255.  
  256.             /* check for signals before going to sleep */
  257.             if (current->signal & ~current->blocked) {
  258.                 if (temp != buf)
  259.                     return temp-buf;
  260.                 else
  261.                     return -EINTR;
  262.             }
  263. #ifdef LP_DEBUG
  264.             printk("lp sleeping at %d characters for %d jiffies\n",
  265.                 lp_total_chars, LP_TIME);
  266.             lp_total_chars=0;
  267. #endif
  268.             current->state = TASK_INTERRUPTIBLE;
  269.             current->timeout = jiffies + LP_TIME;
  270.             schedule();
  271.         }
  272.     }
  273.     return temp-buf;
  274. }
  275. #endif
  276.  
  277.  
  278. #if WHICH_DRIVER == PREFER_INTERRUPT
  279. static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
  280. {
  281.     if (LP_IRQ)
  282.         return lp_write_interrupt(inode, file, buf, count);
  283.     else
  284.         return lp_write_polled(inode, file, buf, count);
  285. }
  286. #endif
  287.  
  288. static int lp_lseek(struct inode * inode, struct file * file,
  289.             off_t offset, int origin)
  290. {
  291.     return -ESPIPE;
  292. }
  293.  
  294. static int lp_open(struct inode * inode, struct file * file)
  295. {
  296.     if (MINOR(inode->i_rdev) >= LP_NO)
  297.         return -ENODEV;
  298.     if (!(LP_F & LP_EXIST))
  299.         return -ENODEV;
  300.     if (LP_F & LP_BUSY)
  301.         return -EBUSY;
  302.  
  303.     LP_F |= LP_BUSY;
  304.  
  305.     ciaa.ddrb = 0xff;    /* set the correct data directions */
  306.     ciab.ddra &= 0xf8;    /* maybe changed in some plip code */
  307.  
  308.     return 0;
  309. }
  310.  
  311. static void lp_release(struct inode * inode, struct file * file)
  312. {
  313.     LP_F &= ~LP_BUSY;
  314. }
  315.  
  316.  
  317. static int lp_ioctl(struct inode *inode, struct file *file,
  318.             unsigned int cmd, unsigned long arg)
  319. {
  320.     unsigned int minor = MINOR(inode->i_rdev);
  321.     int retval = 0;
  322.  
  323. #ifdef LP_DEBUG
  324.     printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
  325. #endif
  326.     if (minor >= LP_NO)
  327.         return -ENODEV;
  328.     if (!(LP_F & LP_EXIST))
  329.         return -ENODEV;
  330.     switch ( cmd ) {
  331.         case LPTIME:
  332.             LP_TIME = arg;
  333.             break;
  334.         case LPCHAR:
  335.             LP_CHAR = arg;
  336.             break;
  337.         case LPABORT:
  338.             if (arg)
  339.                 LP_F |= LP_ABORT;
  340.             else
  341.                 LP_F &= ~LP_ABORT;
  342.             break;
  343.         case LPWAIT:    /* set/get interrupt is ignored, strobe handled by hardware */
  344.         case LPSETIRQ:
  345.         case LPGETIRQ:
  346.             break;
  347.         default:
  348.             retval = -EINVAL;
  349.     }
  350.     return retval;
  351. }
  352.  
  353.  
  354. static struct file_operations lp_fops = {
  355.     lp_lseek,
  356.     NULL,        /* lp_read */
  357.     lp_write,
  358.     NULL,        /* lp_readdir */
  359.     NULL,        /* lp_select */
  360.     lp_ioctl,
  361.     NULL,        /* lp_mmap */
  362.     lp_open,
  363.     lp_release
  364. };
  365.  
  366. long lp_init(long kmem_start)
  367. {
  368.     if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
  369.         printk("unable to get major %d for line printer\n", LP_MAJOR);
  370.         return kmem_start;
  371.     }
  372.  
  373. #if WHICH_DRIVER == FORCE_POLLING
  374.     lp_table.irq = 0;
  375.     printk("lp_init: lp0 using polling driver\n");
  376. #else
  377.  
  378.     if((lp_table.irq = mach_add_isr(IRQ_AMIGA_CIAA_FLG, (isrfunc)lp_interrupt, 0, NULL)))
  379.     {
  380.         lp_table.lp_buffer = (char*)kmem_start;
  381.         kmem_start += LP_BUFFER_SIZE;
  382.         printk("lp_init: lp0 using cia interrupt\n");
  383.     }
  384.     else
  385.  
  386. #if WHICH_DRIVER == PREFER_INTERRUPT
  387.         printk("lp_init: lp0 using polling driver\n");
  388. #else
  389.     {
  390.         printk("cannot get cia interrupt for lp0, and polling driver not configured.\n");
  391.         return kmem_start;
  392.     }
  393. #endif
  394. #endif
  395.  
  396.     LP_F |= LP_EXIST;
  397.     return kmem_start;
  398. }
  399.